package com.huan.es8.runtimefield;

import co.elastic.clients.elasticsearch._types.ScriptLanguage;
import co.elastic.clients.elasticsearch._types.mapping.KeywordProperty;
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch._types.mapping.RuntimeFieldType;
import co.elastic.clients.elasticsearch._types.mapping.TextProperty;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import com.huan.es8.AbstractEs8Api;
import org.junit.jupiter.api.*;

import java.io.IOException;

/**
 * 通过2种方式映射一个runtime field
 * 1. 通过mapping
 * 2. 通过 search request
 * 3. 如果 runtime fields 包含 painless script，则将基于 painless script 计算该字段的值。
 * 如果在没有脚本的情况下创建了 runtime fields，
 * 则系统将在 _source 中查找与该运行时字段名称相同的字段，并将其值用作该 runtime fields 的值。
 *
 * @author huan.fu
 * @date 2023/2/1 - 22:34
 */
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@TestMethodOrder(MethodOrderer.DisplayName.class)
public class MapRuntimeField extends AbstractEs8Api {

    public static final String INDEX_NAME = "index_script_fields1";

    @Test
    @DisplayName("1-通过mapping映射一个 runtime field")
    public void test01() throws IOException {
        client.indices()
                .create(indexRequest ->
                        indexRequest.index(INDEX_NAME)
                                .mappings(mappings ->
                                        mappings.properties("lineId", new Property(new KeywordProperty.Builder().build()))
                                                .properties("lineName", new Property(new TextProperty.Builder().build()))
                                                .runtime("runtimeLineName", runtime ->
                                                        runtime
                                                                .type(RuntimeFieldType.Keyword)
                                                                // 如果此处的脚本没有的话，则从_source中查找runtimeLineName字段的值作为runtime field字段的值
                                                                .script(script ->
                                                                script.inline(inline ->
                                                                        inline.lang(ScriptLanguage.Painless)
                                                                                // runtime field 通过painless脚本需要使用 emit
                                                                                .source("emit(doc['lineName'].value)")
                                                                )
                                                        )
                                                )
                                )
                );
    }

    @Test
    @DisplayName("2-更新mapping的 runtime field")
    public void test02() throws IOException {
        client.indices()
                .putMapping(mapping -> mapping
                        .index(INDEX_NAME)
                        .runtime("runtimeLineName", runtime ->
                                runtime
                                        .type(RuntimeFieldType.Keyword)
                                        .script(script ->
                                        script.inline(inline ->
                                                inline.lang(ScriptLanguage.Painless)
                                                        // runtime field 通过painless脚本需要使用 emit
                                                        .source("emit(doc['lineName'].value + 'update')")
                                        )
                                )
                        ));
    }

    @Test
    @DisplayName("3-通过 search request 构建runtime field")
    public void test04() throws IOException {
        SearchRequest request = SearchRequest.of(searchRequest ->
                searchRequest.index(INDEX_NAME)
                        // 查询所有数据
                        .query(query -> query.matchAll(matchAll -> matchAll))
                        // runtime field字段不会出现在 _source中，需要使用使用 fields api来获取
                        .fields(fields -> fields.field("lineName"))
                        // 创建一个 runtime filed 字段类型是 keyword
                        .runtimeMappings("aggLineName", runtime ->
                                runtime
                                        // 此处给字段类型为keyword
                                        .type(RuntimeFieldType.Keyword)
                                        .script(script ->
                                                script.inline(inline ->
                                                        // runtime field中如果使用 painless脚本语言，需要使用emit
                                                        inline.lang(ScriptLanguage.Painless)
                                                                .source("emit(params['_source']['lineName']+'new')")
                                                )
                                        )
                        )
                        .size(100)
        );

        System.out.println("request: " + request);
        SearchResponse<Object> response = client.search(request, Object.class);
        System.out.println("response: " + response);
    }

}
